package net.hangar5.xmlrpc;

/* XmlWriter.java

The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.mozilla.org/MPL/

Software distributed under the License is distributed on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.

The Original Code is "Hangar5 XMLRPC Library".

The Initial Developer of the Original Code is James D. Rudnicki.  
Portions created by James D. Rudnicki are
Copyright (C) 2001.  All Rights Reserved.

Contributor(s): 
*/
import java.util.*;

/** Converts call return value into an XML-RPC response.
 *
 */
public class XmlWriter extends Object {

  
  /* append values of primative types (i4, double, boolean) to buffer */
  static protected void writeBase64( StringBuffer sb, byte[] baTx ) {
	sb.append( "<value><base64>" );
	char[] caTx;
	caTx = helma.xmlrpc.Base64.encode( baTx );
	sb.append( caTx );
	sb.append( "</base64></value>" );
	return;
  }  
  static protected void writeObject( StringBuffer sb, Object oSend ) throws RpcException{
	if( oSend instanceof Integer ) {
	  writeValue( sb, "i4", ((Integer)oSend).toString() );
	}
	else if( oSend instanceof Boolean ) {
	  String strSend = ((Boolean)oSend).booleanValue() ? "1" : "0";
	  writeValue( sb, "boolean", strSend );
	}
	else if( oSend instanceof Double ) {
	  writeValue( sb, "double", ((Double)oSend).toString() );
	}
	else if( oSend instanceof String ) {
	  writeString( sb, (String)oSend );
	}
  else if( oSend instanceof Date ) {
    writeDate( sb, (Date)oSend );
  }
	else if( oSend instanceof byte[] ) {
	  writeBase64( sb, (byte[])oSend );
	}
	else if( oSend instanceof Vector ) {
	  sb.append( "<value><array><data>" );
	  Vector v = (Vector)oSend;
	  int i, n;
	  n = v.size();
	  for( i=0; i<n; i++ ) {
		Object o = v.elementAt(i);
		writeObject( sb, o );
	  }
	  sb.append( "</data></array></value>" );
	}
	else if( oSend instanceof Hashtable ) {
	  sb.append( "<value><struct>" );
	  Hashtable h = (Hashtable)oSend;
	  int i, n;
	  Enumeration e;
	  e = h.keys();
	  Object oKey;
	  Object oValue;
	  while( e.hasMoreElements() ) {
		oKey = e.nextElement();
		if( oKey instanceof String ) {
		  oValue = h.get( oKey );
		  sb.append( "<member><name>" );
		  sb.append( (String)oKey );
		  sb.append( "</name>" );
		  writeObject( sb, oValue );
		  sb.append( "</member>" );
		}
		else {
		  throw new RpcException( RpcException.BADPARAMTYPE, "Key is not string" );
		}
	  }
	  sb.append( "</struct></value>" );
	}
	else {
	  throw new RpcException( RpcException.BADPARAMTYPE, RpcException.SBADPARAMTYPE );
	}
	
	return;
  }  
  /**
   *
   */
  static protected void writeDate( StringBuffer sb, Date dtValue ) {
    int n;
    String s;
    Calendar c = Calendar.getInstance();
    c.setTime( dtValue );
    
  	sb.append( "<value><dateTime.iso8601>" );
    
    n = c.get( Calendar.YEAR );
    s = Integer.toString( n );
    if( n<10 ) {
      sb.append( "0" );
    }
    sb.append( s );

    sb.append( "-" );
    
    n = c.get( Calendar.MONTH ) + 1;
    s = Integer.toString( n );
    if( n<10 ) {
      sb.append( "0" );
    }
    sb.append( s );
    
    sb.append( "-" );
    
    n = c.get( Calendar.DAY_OF_MONTH );
    s = Integer.toString( n );
    if( n<10 ) {
      sb.append( "0" );
    }
    sb.append( s );
    
    sb.append( "T" );
    
    n = c.get( Calendar.HOUR_OF_DAY );
    s = Integer.toString( n );
    if( n<10 ) {
      sb.append( "0" );
    }
    sb.append( s );
    
    sb.append( ":" );
    
    n = c.get( Calendar.MINUTE );
    s = Integer.toString( n );
    if( n<10 ) {
      sb.append( "0" );
    }
    sb.append( s );
    
    sb.append( ":" );
    
    n = c.get( Calendar.SECOND );
    s = Integer.toString( n );
    if( n<10 ) {
      sb.append( "0" );
    }
    sb.append( s );
    
    sb.append( "</dateTime.iso8601></value>" );
    return;
  }
  
  /* append strings to buffer
   Only different because strings must be escaped */
  static protected void writeString( StringBuffer sb, String strValue ) {
	sb.append( "<value><string>" );
	
	char c;
	int i, n;
	n = strValue.length();
	for( i=0; i<n; i++ ) {
	  c = strValue.charAt(i);

	  if( c == '&') {
		sb.append( "&amp;" );
	  }
	  else if( c == '<' ) {
		sb.append( "&lt;" );
	  }
	  else if( c == '>' ) {
		sb.append("&gt;");
	  }
	  else {
		sb.append(c);
	  }
	}
	
	sb.append( "</string></value>" );
	return;
  }  
  /* append values of primative types (i4, double, boolean) to buffer */
  static protected void writeValue( StringBuffer sb, String strType, String strValue ) {
	sb.append( "<value><" );
	sb.append( strType );
	sb.append( ">" );
	sb.append( strValue );
	sb.append( "</" );
	sb.append( strType );
	sb.append( "></value>" );
	return;
  }  
} // end of class
